#include ".\DxManager.h"


DxManager::DxManager(void)
{
	pD3D = NULL;
 	pd3dDevice = NULL;

	screen_width = 640;
	screen_height = 480;
}

DxManager::~DxManager(void)
{
}

bool DxManager::init(HWND hwnd)
{
if( NULL == ( pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
	{
		lastResult = E_FAIL;
		return false;
	}

	HRESULT hr;

	hr = DirectSoundCreate8( NULL, &g_pDS, NULL );
	if FAILED (hr)
		return false;

	// Set DirectSound cooperative level 
    hr = g_pDS->SetCooperativeLevel( hwnd, DSSCL_PRIORITY );
	if FAILED ( hr )
		return false;

	D3DPRESENT_PARAMETERS d3dpp; 
    ZeroMemory( &d3dpp, sizeof(d3dpp) );
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
	d3dpp.BackBufferCount  = 1;
	d3dpp.BackBufferHeight = screen_height;
	d3dpp.BackBufferWidth  = screen_width;
	d3dpp.hDeviceWindow    = hwnd;
	d3dpp.AutoDepthStencilFormat = D3DFMT_D32;
    d3dpp.EnableAutoDepthStencil = TRUE;

    if( FAILED( pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_REF , hwnd,
                                      D3DCREATE_HARDWARE_VERTEXPROCESSING,
                                      &d3dpp, &pd3dDevice ) ) )
    {
		lastResult = E_FAIL;
        return false;
    }

	pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
	pd3dDevice->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(60, 60, 60));
	pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );


    D3DXVECTOR3 vDir( 0.3f, -1.0f, 1.0f );
    light.Type         = D3DLIGHT_DIRECTIONAL;
    light.Diffuse.r    = light.Diffuse.g  = light.Diffuse.b  = 1.0f;
    light.Specular.r   = light.Specular.g = light.Specular.b = 0.0f;
    light.Ambient.r    = light.Ambient.g  = light.Ambient.b  = 0.3f;
    light.Position     = D3DXVECTOR3( -5.0f, 0.0f, 0.0f );
    D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &vDir );
    light.Attenuation0 = light.Attenuation1 = light.Attenuation2 = 0.0f;
    light.Range        = sqrtf(FLT_MAX);

    pd3dDevice->SetLight(0, &light );
    pd3dDevice->LightEnable(0, TRUE );



	return true;
}

void DxManager::shutdown(void)
{
    if( pd3dDevice != NULL) 
	{
        pd3dDevice->Release();
		pd3dDevice = NULL;
	}
    if( pD3D != NULL)
	{
        pD3D->Release();
		pD3D = NULL;
	}
}

void DxManager::beginRender()
{
	if( NULL == pd3dDevice )
        return;

    // Clear the backbuffer to a black color
    pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );

	pd3dDevice->BeginScene();
}

void DxManager::endRender(void)
{	
	pd3dDevice->EndScene();

	// Present the backbuffer contents to the display
    pd3dDevice->Present( NULL, NULL, NULL, NULL );
}

IDirect3DSurface9* DxManager::loadSurfaceFromBitmap(std::string filename, int width, int height)
{
	HRESULT hResult;
	IDirect3DSurface9* surface = NULL;

	hResult = pd3dDevice->CreateOffscreenPlainSurface(width, height, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &surface, NULL);
	if (FAILED(hResult))
		return NULL;

	hResult = D3DXLoadSurfaceFromFile(surface, NULL, NULL, filename.c_str(), NULL, D3DX_DEFAULT, 0, NULL);
	if (FAILED(hResult))
		return NULL;

	return surface;
}

IDirect3DSurface9* DxManager::getBackBuffer(void)
{
	IDirect3DSurface9* backbuffer = NULL;

	if (!pd3dDevice)
		return NULL;

	HRESULT hResult = pd3dDevice->GetBackBuffer(0,0,D3DBACKBUFFER_TYPE_MONO, &backbuffer);
	if (FAILED(hResult))
		return NULL;
	else
		return backbuffer;
}
void DxManager::blitToSurface(IDirect3DSurface9* srcSurface, const RECT *srcRect, const RECT *destRect)
{
	pd3dDevice->StretchRect(srcSurface, srcRect, getBackBuffer(), destRect, D3DTEXF_NONE);

}

void DxManager::printText(int x, int y, std::string text)
{
	D3DCOLOR fontColor = D3DCOLOR_ARGB(255, 0, 0, 0);
	RECT rct;
	rct.left = x;
	rct.right = x + 180;
	rct.top = y;
	rct.bottom = y + 180;         

	m_font->DrawText(NULL, text.c_str(), -1, &rct, 0, fontColor);
}


//*******************************************************************
//* shutdownDirectSound
//* Releases the DirecSound device
//*******************************************************************/
void DxManager::shutdownDirectSound(void)
{
	if (g_pDS)
	{
		g_pDS->Release();
		g_pDS = NULL;
	}
}

//*******************************************************************
//* LoadWaveToSoundBuffer
//* Loads a wave file into a DirectSound Buffer
//*******************************************************************/
LPDIRECTSOUNDBUFFER DxManager::LoadWaveToSoundBuffer(std::string wavFilename)
{
	LPDIRECTSOUNDBUFFER apDSBuffer = NULL;
	CWaveFile *wavFile;
	HRESULT hr;

	wavFile = new CWaveFile();
	wavFile->Open((char*)wavFilename.c_str(), NULL, WAVEFILE_READ );
	if( wavFile->GetSize() == 0 )
	{
		return false;
	}

	DSBUFFERDESC dsbd;
    ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
    dsbd.dwSize          = sizeof(DSBUFFERDESC);
    dsbd.dwFlags         = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN | DSBCAPS_CTRLFREQUENCY;
    dsbd.dwBufferBytes   = wavFile->GetSize();
    dsbd.guid3DAlgorithm = GUID_NULL;
	dsbd.lpwfxFormat     = wavFile->m_pwfx;

	hr = g_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer, NULL );
	if FAILED (hr)
	{
		MessageBox(NULL, "unable to create sound buffer", "ERROR", MB_OK);
		return NULL;
	}

	VOID*   pDSLockedBuffer      = NULL; // Pointer to locked buffer memory
    DWORD   dwDSLockedBufferSize = 0;    // Size of the locked DirectSound buffer
    DWORD   dwWavDataRead        = 0;    // Amount of data read from the wav file 
	
	hr = apDSBuffer->Lock( 0, wavFile->GetSize(), 
						   &pDSLockedBuffer, &dwDSLockedBufferSize, 
                           NULL, NULL, 0L );
	if FAILED (hr)
        return NULL;

    // Reset the wave file to the beginning 
    wavFile->ResetFile();

	// Read the wave file
    hr = wavFile->Read( (BYTE*) pDSLockedBuffer,
                       dwDSLockedBufferSize, 
                       &dwWavDataRead );
	// Check to make sure that this was successful
	if FAILED (hr)
        return NULL;

	// Check to make sure the wav file is not empty
    if( dwWavDataRead == 0 )
    {
        // Wav is blank, so just fill with silence
        FillMemory( (BYTE*) pDSLockedBuffer, 
                    dwDSLockedBufferSize, 
                    (BYTE)(wavFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
    }
    else if( dwWavDataRead < dwDSLockedBufferSize )
    {
	    // Don't repeat the wav file, just fill in silence 
        FillMemory( (BYTE*) pDSLockedBuffer + dwWavDataRead, 
                   dwDSLockedBufferSize - dwWavDataRead, 
                   (BYTE)(wavFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
    }

    // Unlock the buffer, we don't need it anymore.
    apDSBuffer->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );

	// Clean up
	delete wavFile;

	return apDSBuffer;
}

//*******************************************************************
//* playSound
//* plays a sound currently in a buffer only once
//*******************************************************************/
void DxManager::playSound(LPDIRECTSOUNDBUFFER whichBuffer)
{
	whichBuffer->Play(0, 0, 0);
}

//*******************************************************************
//* playSoundLoop
//* plays a sound in a buffer repeatedly
//*******************************************************************/
void DxManager::playSoundLoop(LPDIRECTSOUNDBUFFER whichBuffer)
{
	whichBuffer->Play( 0, 0, DSBPLAY_LOOPING );
}

//*******************************************************************
//* stopSound
//* stops the sound in this buffer from playing
//*******************************************************************
void DxManager::stopSound(LPDIRECTSOUNDBUFFER whichBuffer)
{
	whichBuffer->Stop();
}

// this is the function that initializes DirectInput
void DxManager::initDInput(HINSTANCE hInstance, HWND hWnd)
{
    // create the DirectInput interface
    DirectInput8Create(hInstance,    // the handle to the application
                       DIRECTINPUT_VERSION,    // the compatible version
                       IID_IDirectInput8,    // the DirectInput interface version
                       (void**)&din,    // the pointer to the interface
                       NULL);    // COM stuff, so we'll set it to NULL

    // create the keyboard device
    din->CreateDevice(GUID_SysKeyboard,    // the default keyboard ID being used
                      &dinkeyboard,    // the pointer to the device interface
                      NULL);    // COM stuff, so we'll set it to NULL

		  // create the mouse device
    din->CreateDevice(GUID_SysMouse,    // the default mouse ID being used
                      &dinmouse,    // the pointer to the device interface
                      NULL);    // COM stuff, so we'll set it to NULL

    dinkeyboard->SetDataFormat(&c_dfDIKeyboard); // set the data format to keyboard format
	dinmouse->SetDataFormat(&c_dfDIMouse);    // set the data format to mouse format

    // set the control you will have over the keyboard
    dinkeyboard->SetCooperativeLevel(hWnd,
                                     DISCL_NONEXCLUSIVE | DISCL_BACKGROUND);

	// set the control you will have over the mouse
    dinmouse->SetCooperativeLevel(hWnd,
                                  DISCL_NONEXCLUSIVE | DISCL_BACKGROUND);

    dinmouse->Acquire();    // Acquire the mouse only once

	D3DXCreateFont( pd3dDevice, 
							20, 
							0, 
							FW_BOLD, 
							0, 
							FALSE, 
							DEFAULT_CHARSET, 
							OUT_DEFAULT_PRECIS, 
							DEFAULT_QUALITY, 
							DEFAULT_PITCH | FF_DONTCARE, 
							TEXT("Arial"), 
							&m_font );

    return;    // return to WinMain()
}

void DxManager::detect_keys(BYTE keystate[])
{
    dinkeyboard->Acquire();    // get access if we don't have it already

    dinkeyboard->GetDeviceState(256, (LPVOID)keystate);    // fill keystate with values	
}

int DxManager::readInput()
{
	detect_keys(kbKeys);
	///////////////READ IN LEFT KEY////////////////
	if(kbKeys[DIK_LEFT] & 0x80)
		activeFlag = activeFlag | MOVE_LEFT;
	else
		activeFlag = activeFlag &(~MOVE_LEFT);
	///////////////READ IN RIGHT KEY///////////////
	if(kbKeys[DIK_RIGHT] & 0x80)
		activeFlag = activeFlag | MOVE_RIGHT;
	else
		activeFlag = activeFlag &(~MOVE_RIGHT);
	///////////////READ IN UP KEY//////////////////
	if(kbKeys[DIK_UP] & 0x80)
		activeFlag = activeFlag | FLIP;
	else
		activeFlag = activeFlag &(~FLIP);
	///////////////READ IN DOWN KEY////////////////
	if(kbKeys[DIK_DOWN] & 0x80)
		activeFlag = activeFlag | DROP;
	else
		activeFlag = activeFlag &(~DROP);
	///////////////READ IN SPACE KEY///////////////
	if(kbKeys[DIK_SPACE] & 0x80)
		activeFlag = activeFlag | SWAP;
	else
		activeFlag = activeFlag &(~SWAP);

	if(detect_mousepos().rgbButtons[0] == 0x80)
		activeFlag = activeFlag | SHOOT;
	else
		activeFlag = activeFlag &(~SHOOT);

	if(kbKeys[DIK_RETURN] & 0x80)
		activeFlag = activeFlag | PAUSE;
	else
		activeFlag = activeFlag &(~PAUSE);
	
	return activeFlag;
}

// this is the function that detets mouse movements and mouse buttons
DIMOUSESTATE DxManager::detect_mousepos()//DIMOUSESTATE mousestate)
{
    //dinmouse->Acquire();    // get access if we don't have it already

    // fill the mousestate with values
    dinmouse->GetDeviceState(sizeof(DIMOUSESTATE), (LPVOID)&mousestate);
    return mousestate;
}

// this is the function that closes DirectInput
void DxManager::cleanDInput(void)
{
    dinkeyboard->Unacquire();    // make sure the keyboard is unacquired
	dinmouse->Unacquire();    // make sure the mouse is unacquired
    din->Release();    // close DirectInput before exiting

    return;
}